package config

import (
	"github.com/redis/go-redis/v9"
	"github.com/spf13/viper"
	"log"
	"os"
	"strings"
	"vben-common/logs"
	"vben-common/utils"
)

var C = InitConfig()

type Config struct {
	viper        *viper.Viper
	SC           *ServerConfig
	EtcdConfig   *EtcdConfig
	LogConfig    *LogConfig
	AppMode      string
	BasePath     string
	ZapLogConfig *utils.LogConfig
	JwtConfig    *JwtConfig
}

type ServerConfig struct {
	Name string
	Addr string
}

type EtcdConfig struct {
	Addrs []string
}

type LogConfig struct {
	GinLogName        string
	GoSkeletonLogName string
	TextFormat        string
	TimePrecision     string
	MaxSize           int64
	MaxBackups        int64
	MaxAge            int64
	Compress          bool
}

type JwtConfig struct {
	SignKey            string
	RefreshSignKey     string
	OnlineUsers        int64
	CreatedExpireAt    int64
	RefreshAllowSec    int64
	RefreshExpireAt    int64
	BindContextKeyName string
	IsCacheToRedis     bool
}

func InitConfig() *Config {
	conf := &Config{
		viper: viper.New(),
	}
	workDir, _ := os.Getwd()
	conf.viper.SetConfigName("app")
	conf.viper.SetConfigType("yaml")
	conf.viper.AddConfigPath("/etc/ms_project/user")
	conf.viper.AddConfigPath(workDir + "/config")
	err := conf.viper.ReadInConfig()
	if err != nil {
		log.Fatalln(err)
	}
	conf.InitBasePath()
	conf.ReadLogConfig()
	conf.ReadServerConfig()
	conf.InitZapLog()
	conf.ReadEtcdConfig()
	conf.InitZapLogConfig()
	conf.ReadJwtConfig()
	conf.ReadRedisConfig()
	return conf
}

func (c *Config) InitBasePath() {
	// 1.初始化程序根目录
	if curPath, err := os.Getwd(); err == nil {
		// 路径进行处理，兼容单元测试程序程序启动时的奇怪路径
		if len(os.Args) > 1 && strings.HasPrefix(os.Args[1], "-test") {
			c.BasePath = strings.Replace(strings.Replace(curPath, `\test`, "", 1), `/test`, "", 1)
		} else {
			c.BasePath = curPath
		}
	}
}

func (c *Config) ReadLogConfig() {
	lc := &LogConfig{}
	lc.GinLogName = c.viper.GetString("logs.ginLogName")
	lc.GoSkeletonLogName = c.viper.GetString("logs.goSkeletonLogName")
	lc.TextFormat = c.viper.GetString("logs.textFormat")
	lc.TimePrecision = c.viper.GetString("logs.timePrecision")
	lc.MaxSize = c.viper.GetInt64("logs.maxSize")
	lc.MaxBackups = c.viper.GetInt64("logs.maxBackups")
	lc.MaxAge = c.viper.GetInt64("logs.maxAge")
	lc.Compress = c.viper.GetBool("logs.compress")
	c.LogConfig = lc
}

func (c *Config) InitZapLog() {
	// 从配置中读取日志配置，初始化日志
	lc := &logs.LogConfig{
		DebugFileName: c.viper.GetString("zap.debugFileName"),
		InfoFileName:  c.viper.GetString("zap.infoFileName"),
		WarnFileName:  c.viper.GetString("zap.warnFileName"),
		MaxSize:       c.viper.GetInt("zap.maxSize"),
		MaxAge:        c.viper.GetInt("zap.maxAge"),
		MaxBackups:    c.viper.GetInt("zap.maxBackups"),
	}
	err := logs.InitLogger(lc)
	if err != nil {
		log.Fatalln(err)
	}
}

func (c *Config) ReadServerConfig() {
	sc := &ServerConfig{}
	sc.Name = c.viper.GetString("server.name")
	sc.Addr = c.viper.GetString("server.addr")
	c.SC = sc
}

func (c *Config) ReadEtcdConfig() {
	ec := &EtcdConfig{}
	var addrs []string
	err := c.viper.UnmarshalKey("etcd.addrs", &addrs)
	if err != nil {
		log.Fatalln(err)
	}
	ec.Addrs = addrs
	c.EtcdConfig = ec
}

func (c *Config) InitZapLogConfig() {
	logCnf := &utils.LogConfig{
		AppMode:       c.AppMode,
		TimePrecision: c.LogConfig.TimePrecision,
		MaxSize:       int(c.LogConfig.MaxSize),
		MaxBackups:    int(c.LogConfig.MaxBackups),
		MaxAge:        int(c.LogConfig.MaxAge),
		Compress:      c.LogConfig.Compress,
		TextFormat:    c.LogConfig.TextFormat,
		BasePath:      c.BasePath,
		LogFileName:   c.LogConfig.GoSkeletonLogName,
	}
	c.ZapLogConfig = logCnf
}

func (c *Config) ReadJwtConfig() {
	jwtConfig := &JwtConfig{}
	jwtConfig.SignKey = c.viper.GetString("Token.jwtTokenSignKey")
	jwtConfig.RefreshSignKey = c.viper.GetString("Token.jwtTokenRefreshSignKey")
	jwtConfig.OnlineUsers = c.viper.GetInt64("Token.jwtTokenOnlineUsers")
	jwtConfig.CreatedExpireAt = c.viper.GetInt64("Token.jwtTokenCreatedExpireAt")
	jwtConfig.RefreshAllowSec = c.viper.GetInt64("Token.jwtTokenRefreshAllowSec")
	jwtConfig.RefreshExpireAt = c.viper.GetInt64("Token.jwtTokenRefreshExpireAt")
	jwtConfig.BindContextKeyName = c.viper.GetString("Token.bindContextKeyName")
	jwtConfig.IsCacheToRedis = c.viper.GetBool("Token.isCacheToRedis")
	c.JwtConfig = jwtConfig
}

func (c *Config) ReadRedisConfig() *redis.Options {
	return &redis.Options{
		Addr:     c.viper.GetString("redis.host") + ":" + c.viper.GetString("redis.port"),
		Password: c.viper.GetString("redis.password"),
		DB:       c.viper.GetInt("redis.db"),
	}
}
